﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Models;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class BlockItemsContainerInfo : SelectableViewModelBase, IAttachTo
    {
        public BlockItemsContainerInfo(BlockDesignerItemViewModel dataItem, bool onlyOneChild, List<string> childFlag) : this(null, dataItem, onlyOneChild, childFlag)
        {

        }

        public BlockItemsContainerInfo(IDiagramViewModel root, BlockDesignerItemViewModel dataItem, bool onlyOneChild, List<string> childFlag) : base(root)
        {
            this.Parent = dataItem;
            this.OnlyOneChild = onlyOneChild;
            this.ChildFlag = childFlag;
        }

        public BlockItemsContainerInfo(IDiagramViewModel root, BlockDesignerItemViewModel dataItem, SelectableItemBase designer) : base(root, designer)
        {
            this.Parent = dataItem;
        }

        public BlockItemsContainerInfo(IDiagramViewModel root, BlockDesignerItemViewModel dataItem, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
        {
            this.Parent = dataItem;
        }

        public override SelectableItemBase GetSerializableObject()
        {
            return new BlockItemsContainerInfoItem(this);
        }

        protected override void Init(IDiagramViewModel root, bool initNew)
        {
            base.Init(root, initNew);
        }

        protected override void InitNew()
        {
            ColorViewModel = new ColorViewModel()
            {
                LineWidth = 1,
                LineColor = new ColorObject() { Color = Color.FromArgb(0xAA, 0x00, 0x00, 0x80) },
                FillColor = new ColorObject() { Color = Colors.Transparent },
            };
        }

        protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
        {
            base.LoadDesignerItemViewModel(designerbase);

            if (designerbase is BlockItemsContainerInfoItem designer)
            {
                this.OnlyOneChild = designer.OnlyOneChild;
                this.ChildFlag = designer.ChildFlag;
                this.PhysicalItemWidth = designer.PhysicalItemWidth;
                this.PhysicalItemHeight = designer.PhysicalItemHeight;
                this.Parameter = new ConstParameter(designer.Parameter);
                if (designer.Children != null)
                {
                    foreach (var child in designer.Children)
                    {
                        BlockDesignerItemViewModel fullyCreatedConnectorInfo = new BlockDesignerItemViewModel(this.Root, child);
                        InsertChild(fullyCreatedConnectorInfo, -1);
                    }
                }
            }
        }

        #region 属性   
        public BlockDesignerItemViewModel DataItem
        {
            get
            {
                return Parent as BlockDesignerItemViewModel;
            }
        }

        public bool OnlyOneChild
        {
            get; set;
        } = true;

        public List<string> ChildFlag
        {
            get; set;
        } = new List<string>();


        private double _itemWidth = double.NaN;
        public double ItemWidth
        {
            get
            {
                return _itemWidth;
            }
            set
            {
                if (value <= 0) return;
                SetProperty(ref _itemWidth, value);
            }
        }

        private double _itemHeight = double.NaN;
        public double ItemHeight
        {
            get
            {
                return _itemHeight;
            }
            set
            {
                if (value <= 0) return;
                SetProperty(ref _itemHeight, value);
            }
        }

        [DisplayName("ItemWidth(mm)")]
        [Browsable(true)]
        public double PhysicalItemWidth
        {
            get
            {
                return ScreenHelper.WidthToMm(ItemWidth);
            }
            set
            {
                ItemWidth = ScreenHelper.MmToWidth(value);
            }
        }

        [DisplayName("ItemHeight(mm)")]
        [Browsable(true)]
        public double PhysicalItemHeight
        {
            get
            {
                return ScreenHelper.WidthToMm(ItemHeight);
            }
            set
            {
                ItemHeight = ScreenHelper.MmToWidth(value);
            }
        }

        private double _actualItemWidth;
        public double ActualItemWidth
        {
            get
            {
                return _actualItemWidth;
            }
            set
            {
                SetProperty(ref _actualItemWidth, value);
            }
        }

        private double _actualItemHeight;
        public double ActualItemHeight
        {
            get
            {
                return _actualItemHeight;
            }
            set
            {
                SetProperty(ref _actualItemHeight, value);
            }
        }

        private ConstParameter _parameter;
        public ConstParameter Parameter
        {
            get
            {
                return _parameter;
            }
            set
            {
                SetProperty(ref _parameter, value);
            }
        }

        private ObservableCollection<BlockDesignerItemViewModel> _children = new ObservableCollection<BlockDesignerItemViewModel>();
        public ObservableCollection<BlockDesignerItemViewModel> Children
        {
            get
            {
                return _children;
            }
            set
            {
                SetProperty(ref _children, value);
            }
        }

        public int ContainerLevel
        {
            get
            {
                if (DataItem.ParentContainer == null)
                {
                    return 0;
                }
                else
                {
                    return DataItem.ParentContainer.ContainerLevel + 1;
                }
            }
        }

        private Func<Point> _getOffSetFunc;
        public Func<Point> GetOffSetFunc
        {
            get
            {
                return _getOffSetFunc;
            }
            set
            {
                SetProperty(ref _getOffSetFunc, value);
            }
        }

        private bool _beAttachTo;
        public bool BeAttachTo
        {
            get
            {
                return _beAttachTo;
            }
            set
            {
                SetProperty(ref _beAttachTo, value);
            }
        }

        private bool _disableAttachTo;
        public bool DisableAttachTo
        {
            get
            {
                return _disableAttachTo;
            }
            set
            {
                SetProperty(ref _disableAttachTo, value);
            }
        }

        public virtual bool CanAttachTo(BlockDesignerItemViewModel item)
            => item != null && item != this.DataItem && !item.IsReadOnly && (this.ChildFlag == null || this.ChildFlag.Count == 0 || this.ChildFlag.Contains(item.Flag));
        #endregion


        public double GetItemWidth()
        {
            return double.IsNaN(ItemWidth) ? ActualItemWidth : ItemWidth;
        }

        public double GetItemHeight()
        {
            return double.IsNaN(ItemHeight) ? ActualItemHeight : ItemHeight;
        }

        public void InsertChild(BlockDesignerItemViewModel child, int index)
        {
            child.ParentContainer = this;
            if (index == -1)
            {
                Children.Add(child);
            }
            else
            {
                Children.Insert(index, child);
            }
        }

        public void RemoveChild(BlockDesignerItemViewModel child)
        {
            child.ParentContainer = null;
            Children.Remove(child);
        }

        public List<BlockItemsContainerInfo> GetAllContainers(ObservableCollection<BlockDesignerItemViewModel> children, bool self)
        {
            List<BlockItemsContainerInfo> itemsContainers = new List<BlockItemsContainerInfo>();
            if (self)
            {
                itemsContainers.Add(this);
            }
            if (children != null)
            {
                foreach (var item in children)
                {
                    if (item.Containers != null)
                    {
                        foreach (var container in item.Containers)
                        {
                            itemsContainers.Add(container);
                            itemsContainers.AddRange(container.GetAllContainers(container.Children, false));
                        }
                    }
                }
            }
            return itemsContainers;
        }

        public RectangleBase GetBounds()
        {
            var offset = GetOffSetFunc?.Invoke() ?? new Point(0, 0);

            var containBound = new RectangleBase(DataItem.Left + offset.X, DataItem.Top + offset.Y, GetItemWidth(), GetItemHeight());
            double height = 0;
            foreach (var child in Children)
            {
                child.Left = DataItem.Left + offset.X;
                child.Top = DataItem.Top + offset.Y + height;
                height += child.GetItemHeight();
            }

            return containBound;
        }

        public object GetResult()
        {
            if (OnlyOneChild)
            {
                if (Children?.Count == 1)
                {
                    return Children.FirstOrDefault()?.GetResult();
                }
                else
                {
                    return Parameter?.Value;
                }
            }
            else
            {
                return null;
            }
        }

        public override void Dispose()
        {
            base.Dispose();

            foreach (var child in Children)
            {
                child.Dispose();
            }
        }
    }
}
